- Friday, October 4, 2024
In the realm of React development, a common feature request is to make application screens shareable via URLs. This request often leads to bugs, particularly when managing state within React components. A practical example of this is a searchable table that fetches data from a server. The initial implementation uses local React state to manage the search input, which works well until the page is reloaded. Upon reloading, the search text and table data are lost, highlighting the need for a solution that allows the state to persist through URL parameters. To address this, the approach involves syncing the React state with the URL. By utilizing the `useEffect` hook, developers can update the URL whenever the search input changes. In a Next.js application, this can be achieved by leveraging the `useRouter` and `usePathname` hooks to modify the URL dynamically based on the search input. However, this creates a new challenge: when the page is reloaded, the UI does not reflect the URL's state, leading to inconsistencies. To resolve this, the `useSearchParams` hook can be employed to initialize the search state from the URL parameters. This ensures that when the page is loaded or reloaded, the search input reflects the current URL state. However, this introduces a potential issue with state duplication, as both the React state and the URL can hold the search text, leading to synchronization problems when navigating with the browser's back and forward buttons. The solution lies in treating the URL as the single source of truth for the search text. By removing the local React state and deriving the search text directly from the URL parameters, developers can eliminate the risk of state duplication. This means that any changes made in the input field will directly update the URL, and vice versa, ensuring that the UI remains consistent across different interactions, including page reloads and navigation. The final implementation allows for seamless interaction: typing in the search box updates the URL, and refreshing the page or using the back and forward buttons keeps the search input and table data in sync. Additionally, if the search input is cleared, the URL is reset accordingly, maintaining a clean and functional user experience. This approach emphasizes the importance of having a single source of truth in applications, particularly when dealing with dynamic data that exists outside of React, such as URL parameters. By recognizing and eliminating duplicated state, developers can create more robust and maintainable applications. The discussion also touches on broader concepts of state management in React, suggesting that as applications evolve, state may need to be lifted to external systems, reinforcing the idea that understanding how to manage state effectively is crucial for React developers. In conclusion, the article highlights the significance of syncing React components with URL parameters to create shareable and consistent user experiences. It encourages developers to be mindful of state management practices and to consider external sources of truth when designing their applications. The author also hints at further exploration of these concepts in an upcoming course focused on advanced React patterns, promising to delve deeper into state management and other core React principles.
- Monday, August 12, 2024
This article explains how to create a simple React state management library using the `useSyncExternalStore` hook introduced in React 18. It outlines the key components of the library, including subscribing to state changes, retrieving the current state, and updating the state. The article also compares this approach to using React Context and discusses potential improvements like using reducers and immer for state management.
- Friday, September 27, 2024
In the realm of React development, achieving better component decoupling is essential for creating maintainable and reusable code. A common scenario involves an onboarding component that transitions through various steps, such as WelcomeStep, TermsOfServiceStep, and CompleteStep. A typical implementation might involve a state variable to track the current step and pass a state setter function down to child components. While this approach works, it introduces tight coupling between the parent and child components, which can lead to several issues. The tight coupling arises because the child components gain direct access to the parent's internal state management. This can break encapsulation, making it difficult to troubleshoot issues since the parent loses control over how its state is modified. If a child component can change the parent's state in unexpected ways, it complicates debugging and can lead to unintended side effects. Additionally, this setup can result in unnecessary re-renders, as the child components dictate when the parent should update its state, rather than the parent controlling its own updates. To address these concerns, a more effective solution is to have the child components provide callback functions to the parent. This approach allows the parent to maintain control over its state while still enabling the child components to signal when an action should occur. For instance, instead of passing a setter function directly, the parent can pass a callback like `onClickNext`, which the child can invoke when it needs to trigger a state change. This method not only reduces coupling but also enhances the reusability and testability of the child components. A practical example of this revised approach can be seen in the updated implementation of the onboarding component. The parent component retains the state management but now calls the setter function within its own context, using the callback provided by the child. This design allows for more complex logic to be incorporated into the callback if needed, while also simplifying the interface of the child components. When designing components, it is crucial to consider their interfaces carefully. By thinking of components in isolation, developers can create simpler, more intuitive, and reusable components that are easier to test. This focus on decoupling and interface design ultimately leads to a more robust and maintainable codebase, enhancing the overall development experience in React.
- Thursday, August 15, 2024
This article introduces three key rules to manage React side effects properly: keep side effects out of the render process, place side effects triggered by events in event handlers, and use useEffect to handle side effects that synchronize with external systems.
- Tuesday, May 28, 2024
This article presents a way to implement React-like component-based frontend development in Go using the standard library. Its approach defines components using the define function, composes them using templates, and manages state using URL query parameters.
- Building a React-like library from scratch to understand its internal workings and design decisions.Monday, September 2, 2024
This article details the process of building a React-like library from scratch, providing insights into its internal workings and design decisions. It starts by implementing a core rendering model, including components, virtual DOM, and reconciliation, showing how React constructs and updates the UI. It then goes into the implementation of essential hooks like `useState`, `useRef`, `useEffect`, and `useMemo`. Finally, the article discusses the implementation of `useCallback` and `useContext`, showing off the challenges and solutions involved in managing state and context sharing within a component tree.
- Thursday, May 16, 2024
This article explains how to build a simplified version of React with 400 lines of code. The simplified React utilizes Fiber architecture and concurrency mode to avoid blocking the main thread during rendering. It is able to execute tasks during browser idle time. It uses a linked list structure to connect work units and triggers updates through a custom useState implementation.
- Monday, March 4, 2024
Legend State is a React state management library optimized for offline-first persistence. Expo is a React Native mobile app development framework. Offline-first applications have challenges like conflict resolution to deal with. This tutorial walks readers through how to deal with offline sync, offline conflicts, real-time collaboration, and other common offline-first challenges.
- Thursday, September 26, 2024
The blog post discusses the concept of component composition in React, emphasizing its significance as a core advantage of the framework. Initially, the author reflects on their early experiences with React, highlighting features like the Virtual DOM, one-way data flow, and JSX. However, they argue that the true strength of React lies in its ability to compose components into more complex structures, a practice that was not widely accepted in software development a decade ago. The author addresses the traditional notion of separation of concerns, suggesting that while it still exists, it has evolved. Instead of separating styles, logic, and markup into distinct layers, React encourages grouping them together within components, leading to better code cohesion. This shift allows developers to think in terms of components, which can enhance the organization and maintainability of code. The discussion then shifts to conditional rendering, a common practice in React where components are rendered based on certain conditions. The author presents an example of a `ShoppingList` component that conditionally renders user information and items based on the presence of data. While this approach is acceptable for simple cases, the author warns that it can become problematic when managing multiple states within a single component. As the complexity of the component increases, the author illustrates how conditional rendering can lead to a convoluted structure that is difficult to read and maintain. They propose breaking down the component into smaller, more manageable pieces, suggesting the use of a layout component to encapsulate shared elements while allowing for dynamic content based on the component's state. The author advocates for using early returns to handle different states of a component more clearly. By returning early for each state (e.g., loading, no data, or displaying data), the code becomes easier to follow and reduces cognitive load. This method also facilitates the addition of new conditions, such as error handling, without complicating the existing logic. The post concludes by emphasizing the importance of component composition and the need to avoid excessive conditional rendering. The author encourages developers to embrace early returns and to continually reassess their component structures to ensure clarity and maintainability. They invite readers to engage with them for further discussion or questions, reinforcing the community aspect of learning and sharing knowledge in the React ecosystem.
- Tuesday, May 14, 2024
React Query is both a data fetcher and an asynchronous state manager designed for handling server state. Unlike client state (managed with useState or useReducer), server state is often asynchronous, persistent, and can be modified by multiple users. React Query abstracts common complexities like cache management, invalidation, and refetching, allowing developers to focus on building their applications without getting bogged down in the complex, nitty-gritty details of data fetching.
- Friday, September 6, 2024
React 19 beta introduces new hooks like useTransition and useActionState to streamline async handling, improve form management, and enable optimistic updates for smoother user experiences. These features reduce unnecessary re-renders, automate state management, and improve UI responsiveness during async operations.
- Friday, August 2, 2024
React introduced the concept of a "virtual DOM" to optimize web app rendering. Its popularity led to widespread adoption, but also to criticisms regarding its learning curve, state management, and performance. While React's defenders highlight its improvements in recent versions, alternative frameworks like Svelte and Astro offer simpler approaches without relying on the virtual DOM.
- Friday, October 4, 2024
React hooks have become an integral part of modern React development, yet there are nuances and unspoken rules that can complicate their use. Tom MacWright shares his insights on these complexities, particularly focusing on the useEffect hook and its dependency management. One of the primary rules regarding useEffect is that the dependency array should include all variables referenced within the callback function. For instance, if a developer uses a state variable like `x` in a useEffect without including it in the dependency array, it can lead to unexpected behavior. The correct implementation would ensure that `x` is included in the dependencies, thus allowing React to track changes to that variable effectively. However, not all values need to be included in the dependency array. Some values are considered "known to be stable," meaning they do not change between renders. Examples of these stable values include state setters from useState, dispatchers from useReducer, refs from useRef, and certain return values from hooks like useEffectEvent. These stable references do not need to be added to the dependencies array, which can simplify the management of effects. MacWright expresses frustration with the lack of clarity in React's documentation regarding the stability of these values. The reliance on object identity and stability can lead to confusion, especially for developers who may not be aware of the implications of including unstable references in the dependency array. This can result in effects running more frequently than intended, which can degrade performance and lead to bugs. The documentation does touch on some aspects of stability, but it is often scattered across different sections rather than being consolidated in the API documentation for each hook. This can make it challenging for developers to ascertain whether the return values from third-party hooks, such as those from libraries like Jotai or tanstack-query, are stable. The uncertainty surrounding these third-party hooks adds another layer of complexity to dependency management in React. Despite these challenges, MacWright notes that including stable values in the dependency array is not detrimental; it simply means that the effect will not trigger unnecessarily. However, he advocates for clearer documentation and better tools to help developers understand which values are stable and which are not. This would enhance the overall experience of working with React hooks and improve the reliability of applications built with them.
- Friday, September 13, 2024
React 19 introduces major updates like Server Components, improving performance by rendering on the server and reducing client-side JavaScript. New features include Actions for handling events and enhanced hooks like useActionState for managing form states, streamlining both server and client workflows.
- Thursday, June 6, 2024
This blog post explores different architectures for building real-time collaborative applications with a central server. It discusses the challenges of server-side rebasing and solutions. The post also delves into the complexities of handling text and list editing in collaborative apps and recommends using optimistic local updates to improve user experience.
- Monday, April 15, 2024
A new official React doc that explains how to animate a progress element using the new useTransition hook, which lets you update state without blocking UI.
- Wednesday, July 31, 2024
While using useEffect for data fetching is common, it can lead to several issues, including race conditions, out-of-order responses, and inconsistent UI states. Remix's loader function, which provides built-in request cancellation, race condition prevention, and a smooth user experience, handles data fetching seamlessly. It also allows for custom loading states and provides flexibility and control over the user interface. Remix also has pre-rendering capabilities that deliver pre-rendered HTML with data included.
- Wednesday, May 8, 2024
React Query and React Context can be used together to manage data dependencies and make component logic simpler. Combining both makes implicit dependencies (like knowing a query has been executed elsewhere) clear and visible in your code.
- Friday, October 4, 2024
Synchronizing reactive local-first applications involves a strategic approach to ensure that data remains consistent and up-to-date across different environments. This process is essential for applications that prioritize user experience by allowing offline access and local data storage while still needing to sync with a central server or other devices when connectivity is available. TinyBase is a framework that can facilitate this synchronization process. It provides tools and documentation to help developers implement local-first strategies effectively. By leveraging TinyBase, developers can create applications that maintain a reactive state, meaning that any changes made locally are immediately reflected in the user interface, enhancing the overall user experience. The Expo platform offers a variety of resources for developers looking to build and deploy applications. It includes tools like Expo CLI and Expo Go, which streamline the development process and allow for easy testing and deployment of applications. The Expo Dashboard serves as a central hub for managing projects, while the community resources, such as Discord and job boards, foster collaboration and support among developers. In addition to technical resources, Expo emphasizes the importance of legal and compliance considerations. They provide clear guidelines on terms of service, privacy policies, and community standards to ensure that developers are informed and compliant with regulations. Overall, the integration of local-first principles with tools like TinyBase and the support provided by platforms like Expo creates a robust environment for developing modern applications that prioritize user experience and data integrity.
- Thursday, May 23, 2024
React 19 has features like Server Components and Server Actions, which optimize performance and simplify data handling by shifting more logic to the server. Server Actions make API endpoint creation and form handling easier by automatically managing pending UI states, error handling, and optimistic UI updates.
- Thursday, April 25, 2024
An in-depth YouTube tutorial on modern React.
- Thursday, May 2, 2024
Excessive null/undefined value checking in React components is difficult to deal with as a codebase grows, especially if the codebase is poorly typed.
- Friday, March 8, 2024
Meta’s react-strict-dom (open sourced last week) is an experimental integration of React DOM and StyleX that standardizes the development of styled React components, both web and native. This article goes into the historical background of building a universal codebase that shares components between Web and Native and how react-strict-dom changes the way we can do it. You might need to refresh the page to get it to load!
- Wednesday, May 15, 2024
The Asynchronous State Handler pattern improves UX in web apps by decoupling data fetching from the UI. It wraps asynchronous queries with meta-queries that track the status (loading, success, error) of the data fetching process. This allows the UI to react dynamically to these states, displaying loading indicators or error messages when needed. The pattern can be implemented in React using a custom hook.
- Tuesday, April 9, 2024
Optimistic UI is a technique used to improve the perceived performance of web applications by updating the UI instantly in response to user actions, even before getting a response from the server. React's experimental hook useOptimistic() simplifies the implementation of Optimistic UI by providing a way to manage temporary optimistic state alongside the true state. Internally, useOptimistic() leverages React's update mechanism but adds a special revertLane for easy switching between optimistic and true states.
- Friday, August 9, 2024
This is a practical guide to refactoring a messy React component through gradual improvements. First, one should make sure that tests are written so that no functional changes occur during refactoring. Then, linting rules should be used to prevent future code duplication and dead code. The guide highlights several key areas for refactoring, including splitting components based on responsibilities and extracting utility functions to improve code organization and maintainability.
- Wednesday, March 6, 2024
React 19 introduces several significant improvements designed to streamline development and boost application performance. Key features include a performance-enhancing compiler, simplified form handling with Actions, server-side rendering optimizations with Server Components, and better integration with Web Components. The update promises faster rendering, smoother user experiences, and easier development workflows.
- Friday, July 26, 2024
Airbnb faced challenges upgrading its massive React codebase due to dependency management and performance concerns. To overcome these, its team developed a React Upgrade System that enabled incremental upgrades, module aliasing, environment targeting, and rigorous testing. The system allowed Airbnb to smoothly transition to React 18 while maintaining code quality and user experience.
- Tuesday, June 18, 2024
React 19 introduced a change that disables parallel rendering of siblings within the same Suspense boundary. This could have potentially degraded performance for many websites that rely on React, but after facing pushback from the community, the React team decided to revert this change.
- Friday, May 24, 2024
In React, closures combined with the useCallback hook can cause hidden memory leaks by holding onto large objects in the component's context, preventing garbage collection. Memoized functions may inadvertently reference each other and shared data, creating an endless chain of closures. To avoid such issues, keep closure scopes small, avoid unnecessary memoization, and consider using useRef for large objects.